//集团里有 n 名员工，他们可以完成各种各样的工作创造利润。 
//
// 第 i 种工作会产生 profit[i] 的利润，它要求 group[i] 名成员共同参与。如果成员参与了其中一项工作，就不能参与另一项工作。 
//
// 工作的任何至少产生 minProfit 利润的子集称为 盈利计划 。并且工作的成员总数最多为 n 。 
//
// 有多少种计划可以选择？因为答案很大，所以 返回结果模 10^9 + 7 的值。 
//
// 
// 
// 
//
// 示例 1： 
//
// 
//输入：n = 5, minProfit = 3, group = [2,2], profit = [2,3]
//输出：2
//解释：至少产生 3 的利润，该集团可以完成工作 0 和工作 1 ，或仅完成工作 1 。
//总的来说，有两种计划。 
//
// 示例 2： 
//
// 
//输入：n = 10, minProfit = 5, group = [2,3,5], profit = [6,7,8]
//输出：7
//解释：至少产生 5 的利润，只要完成其中一种工作就行，所以该集团可以完成任何工作。
//有 7 种可能的计划：(0)，(1)，(2)，(0,1)，(0,2)，(1,2)，以及 (0,1,2) 。 
// 
// 
//
// 
//
// 提示： 
//
// 
// 1 <= n <= 100 
// 0 <= minProfit <= 100 
// 1 <= group.length <= 100 
// 1 <= group[i] <= 100 
// profit.length == group.length 
// 0 <= profit[i] <= 100 
// 
// Related Topics 数组 动态规划 👍 247 👎 0


package leetcode.editor.cn;

/**
 * 盈利计划
 * @date 2022-06-30 13:05:17
 */
class P879_ProfitableSchemes{
	 public static void main(String[] args) {
	 	 //测试代码
	 	 Solution solution = new P879_ProfitableSchemes().new Solution();
	 }
	 
//力扣代码
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
		 //二维解决
		 int mod = (int) (1e9 + 7);//n名员工，m组任务
	//dp[i][j][k] 为考虑前 i 个任务，使用人数不超过 j，所得利润至少为 k 的方案数。
    public int profitableSchemes(int n, int minProfit, int[] group, int[] profit) {
		int m = group.length;
		long[][][] dp = new long[m+1][n+1][minProfit+1];
		//初始化  不考虑任务利润为0的情况下 方案数是1种
		for (int i = 0; i <=n ; i++) {
			dp[0][i][0] = 1;
		}
		for (int i = 1; i <=m ; i++) {//遍历任务数
			for (int j = 0; j <=n; j++) {//遍历人员
				for (int k = 0; k <=minProfit ; k++) {//遍历利润
					dp[i][j][k] = dp[i-1][j][k];//不选i个任务
					if(j >= group[i-1]){//人数大于任务需要的人数，选i个任务
						/**
						 * 所有的任务利润都为“非负数”，所以不可能出现利润为负的情况，
						 * 这时候「利润至少为某个负数 k」的方案数其实是完全等价于利润至少为 0的方案数。
						 */
						dp[i][j][k] += dp[i-1][j - group[i-1]][Math.max(k - profit[i-1],0)];
					}
					if(dp[i][j][k] >= mod){
						dp[i][j][k]-=mod;
					}
				}
			}
		}
		return (int) dp[m][n][minProfit];
    }
}
//leetcode submit region end(Prohibit modification and deletion)
class Solution1 {
	//一维解决
	int mod = (int) (1e9 + 7);//n名员工，m组任务
	public int profitableSchemes(int n, int minProfit, int[] group, int[] profit) {
		int m = group.length;
		int[][] dp = new int[n+1][minProfit+1];
		for (int i = 0; i <=n ; i++) {
			dp[i][0] = 1;
		}
		for (int i = 1; i <=m; i++) {//m个任务
			for (int j = n; j >= group[i-1] ; j--) {
				for (int k = minProfit; k >=0 ; k--){
					dp[j][k] += dp[j - group[i-1]][Math.max(0,k-profit[i-1])];
					if(dp[j][k] >= mod){
						dp[j][k]-= mod;
					}
				}
			}
		}
		return dp[m][minProfit];
	}
}
}
